package com.snif.web.attach.core.service;

import cn.hutool.core.util.ClassUtil;


import cn.hutool.json.JSONUtil;
import com.snif.web.attach.core.config.MethodConfig;
import com.snif.web.attach.core.utils.ClassTik;
import com.snif.web.attach.core.utils.LogUtils;
import com.snif.web.attach.core.utils.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;


import java.lang.reflect.Method;
import java.util.List;

/**
 * MethodInvoker
 *
 * @author Yakir
 */

public class MethodInvokeService {
	public static void reportUsage() {
		try {
			String json="{\n" +
					"        \"id\": \"test1\",\n" +
					"        \"clazz\": \"com.snif.task.job.TrustPushJob\",\n" +
					"        \"method\": \"POST\",\n" +
					"        \"methodName\": \"trustPushJob\",\n" +
					"        \"contentType\":\"application/x-www-form-urlencoded\",\n" +
					"        \"params\":[\n" +
					"          {\n" +
					"            \"paramName\":\"params\",\n" +
					"            \"paramType\":\"String\"\n" +
					"          }\n" +
					"        ]\n" +
					"    }";
			MethodConfig config = JSONUtil.toBean(json, MethodConfig.class);
			MethodInvokeService methodInvokeService = new MethodInvokeService();
			Object o = methodInvokeService.invokeMethod(config, new Object[]{""});
			System.out.println("执行结果"+JSONUtil.toJsonStr(o));
		} catch (Throwable t) {
			//ignore
		}
	}
	/**
	 * 调用Spring Bean中的方法
	 * @param config 方法配置信息
	 * @param params 方法参数
	 * @return 方法调用结果
	 * @throws Exception 调用过程中的异常
	 */
	public Object invokeMethod(MethodConfig config, Object[] params) throws Exception {
		// 验证参数长度
		int cfgParamLen = config.getParams() == null ? 0 : config.getParams().size();
		if (params.length != cfgParamLen) {
			throw new IllegalArgumentException("参数长度不匹配，期望: " + cfgParamLen + ", 实际: " + params.length);
		}

		// 1. 尝试多种方式加载目标类
		Class<?> targetClass = loadTargetClass(config.getClazz());

		System.out.println("成功加载目标类:"+config.getClazz());

		// 从Spring容器获取Bean实例
		Object beanInstance = getBeanInstance(targetClass);

		// 获取参数类型数组
		Class<?>[] paramTypes = determineParamTypes(config, params);

		// 获取目标方法
		Method targetMethod = targetClass.getMethod(config.getMethodName(), paramTypes);

		LogUtils.info("执行方法:{},参数:{}", config.getMethodName(), params);
		// 调用方法
		return targetMethod.invoke(beanInstance, params);
	}

	private Class<?> loadTargetClass(String clazz) {
		return ClassUtil.loadClass(clazz);
	}

	/**
	 * 从Spring容器获取Bean实例 先尝试按类型获取，失败则按类名首字母小写尝试获取
	 */
	private Object getBeanInstance(Class<?> targetClass) {
		try {
			// 尝试按类型获取Bean
			return SpringContextHolder.getBean(targetClass);

		}
		catch (Exception e) {
			System.out.println("按类型获取Bean失败:"+targetClass.getName()+"尝试按名称获取");
			// 按类名首字母小写尝试获取
			String className = targetClass.getSimpleName();
			String beanName = Character.toLowerCase(className.charAt(0)) + className.substring(1);
			try {
				return SpringContextHolder.getBean(beanName);
			}
			catch (Exception e2) {
				System.out.println("按名称获取Bean也失败:"+beanName);
				throw new RuntimeException("无法从Spring容器获取Bean实例: " + targetClass.getName(), e2);
			}
		}
	}

	private Class<?>[] determineParamTypes(MethodConfig config, Object[] params) {
		List<MethodConfig.ParamMeta> paramsList = config.getParams();
		Class<?>[] types = new Class<?>[params.length];
		for (int i = 0; i < params.length; i++) {
			MethodConfig.ParamMeta paramMeta = paramsList.get(i);
			String paramType = paramMeta.getParamType();
			types[i] = ClassTik.getTypeClass(paramType);
		}
		return types;
	}

}
